#ifndef UNIQUE_PTR_HPP
#define UNIQUE_PTR_HPP

#include <cstdint>
#include <functional>
namespace MyUnique_ptr
{
    template <typename T>
    class Unique_ptr
    {
    public:
        explicit Unique_ptr(T *ptr = nullptr, std::function<void(T *)> deleter = [](T *p)
                                              { delete p; })
            : _ptr(ptr), _del(deleter)
        {
        }

        Unique_ptr(Unique_ptr &&other) : _ptr(other._ptr), _del(std::move(other._del))
        {
            other._ptr = nullptr;
        }
        Unique_ptr &operator=(Unique_ptr &&other)
        {
            if (this != other)
            {
                reset();
                _ptr = other._ptr;
                _del = std::move(other._del);
                other._ptr = nullptr;
            }
            return *this;
        }
        Unique_ptr(const Unique_ptr &) = delete;
        Unique_ptr &operator=(const Unique_ptr &) = delete;
        ~Unique_ptr()
        {
            if (_ptr != nullptr)
                _del(_ptr);
        }

    public:
        T *get() { return _ptr; }
        T *release()
        {
            T *temp = _ptr;
            _ptr = nullptr;
            return temp;
        }
        T &operator*() const { return *_ptr; }
        T *operator->() const { return _ptr; }
        void reset(T *ptr = nullptr)
        {
            if (_ptr != nullptr)
            {
                _del(_ptr);
            }
            _ptr = ptr;
        }
        explicit operator bool() const { return _ptr != nullptr; }

    private:
        T *_ptr;
        std::function<void(T *)> _del; // 删除器
    };

    // 一个特化版本，管理数组的unique_ptr
    // 其余函数和上面的一样
    template <typename T>
    class Unique_ptr<T[]>
    {
    public:
        explicit Unique_ptr(T *ptr, std::function<void(T *)> deleter = [](T *p)
                                    { delete[] p; }) {}

        T &operator[](std::size_t index) const { return _ptr[index]; }

    private:
        T *_ptr;
        std::function<void(T *)> _del; // 删除器
    };

    template <typename T, typename... Args>
    Unique_ptr<T> make_Unique(Args &&...args)
    {
        return Unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
    template <typename T, typename... Args>
    Unique_ptr<T[]> make_Unique(std::size_t size)
    {
        return Unique_ptr<T[]>(new T[size]);
    }
}

#endif